import Axios, {
  type AxiosInstance,
  type AxiosRequestConfig,
  type CustomParamsSerializer
} from "axios";
import type {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { useUserStoreHook } from "@/store/modules/user";
import {
  type EventSourceMessage,
  fetchEventSource
} from "@microsoft/fetch-event-source";
import { EventType } from "@/types/sse.types";
// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 10000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
};

// SSE 连接配置接口
interface SSEConfig {
  /** 连接成功回调 */
  onOpen?: (response: Response) => void;
  /** 接收到消息回调 */
  onMessage: (message: EventSourceMessage) => void;
  /** 错误回调 */
  onError?: (error: Error) => void;
  /** 连接关闭回调 */
  onClose?: () => void;
  /** 心跳检测配置 */
  heartbeat?: {
    /** 心跳超时时间（毫秒），超过该时间未收到消息则关闭连接 */
    timeoutMs?: number;
    /** 心跳检测间隔（毫秒） */
    checkIntervalMs?: number;
  };
}

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前`Axios`实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 刷新中标记与队列（single-flight） */
  private static isRefreshing = false;

  /** `token`过期后，暂存待执行的请求 */
  private static requests = [];

  /** 重连原始请求 */
  private static retryOriginalRequest(config: PureHttpRequestConfig) {
    return new Promise(resolve => {
      PureHttp.requests.push((token: string) => {
        config.headers["Authorization"] = token;
        resolve(config);
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 开启进度条动画，除非设置 skipProgress 为 true
        if (!config.skipProgress) {
          NProgress.start();
        }
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }
        // 是否跳过认证头
        if (config.skipAuth) {
          return config;
        }

        // 如果accessToken不存在或已过期
        if (useUserStoreHook().isAccessTokenExpired()) {
          if (PureHttp.isRefreshing) {
            return PureHttp.retryOriginalRequest(config);
          } else {
            PureHttp.isRefreshing = true;
            try {
              // 尝试刷新accessToken
              await useUserStoreHook().refreshAccessToken();
              // 重放请求
              PureHttp.requests.forEach(cb =>
                cb(useUserStoreHook().getFormattedToken())
              );
              PureHttp.requests = [];
            } finally {
              PureHttp.isRefreshing = false;
            }
          }
          PureHttp.isRefreshing = false;
        }

        // 添加 token 到请求头
        config.headers["Authorization"] =
          useUserStoreHook().getFormattedToken();

        return config;
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        const $config = response.config;
        // 关闭进度条动画
        NProgress.isStarted() ? NProgress.done() : null;

        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        return response.data;
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.isStarted() ? NProgress.done() : null;

        if ($error.response.status === 401) {
          useUserStoreHook().logOut();
        }

        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的`post`工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    config?: PureHttpRequestConfig
  ): Promise<T> {
    return this.request<T>("post", url, params, config);
  }

  /** 单独抽离的`get`工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    config?: PureHttpRequestConfig
  ): Promise<T> {
    return this.request<T>("get", url, params, config);
  }

  /** 创建SSE连接 */
  public createSSEConnection(
    url: string,
    config: SSEConfig,
    params?: Record<string, any>
  ): { close: () => void } {
    let controller: AbortController | null = new AbortController();

    // 处理URL参数
    if (params && Object.keys(params).length > 0) {
      const queryString = new URLSearchParams(params).toString();
      url = `${url}${url.includes("?") ? "&" : "?"}${queryString}`;
    }

    const headers: HeadersInit = {
      Accept: "text/event-stream"
    };

    // 获取token
    const token = useUserStoreHook().getFormattedToken();
    if (token) {
      headers["Authorization"] = token;
    }

    // 心跳检测配置
    const heartbeatConfig = config.heartbeat || {
      timeoutMs: 6000, // 默认6秒超时
      checkIntervalMs: 3000 // 默认3秒检查一次
    };

    // 心跳检测相关
    let lastEventTimestamp = Date.now();
    let heartbeatCheckTimer: ReturnType<typeof setInterval> | null = null;

    // 启动心跳检测
    const startHeartbeatCheck = () => {
      lastEventTimestamp = Date.now();

      if (heartbeatCheckTimer) {
        clearInterval(heartbeatCheckTimer);
      }

      heartbeatCheckTimer = setInterval(() => {
        const now = Date.now();
        const timeSinceLastEvent = now - lastEventTimestamp;

        if (timeSinceLastEvent > heartbeatConfig.timeoutMs) {
          console.warn(
            `No events received for ${timeSinceLastEvent}ms, exceeding timeout of ${heartbeatConfig.timeoutMs}ms. Closing connection.`
          );

          // 清理定时器
          if (heartbeatCheckTimer) {
            clearInterval(heartbeatCheckTimer);
            heartbeatCheckTimer = null;
          }

          // 关闭连接
          if (controller) {
            controller.abort();
            controller = null;
          }

          // 手动调用onClose回调
          if (config.onClose) {
            config.onClose();
          }
        }
      }, heartbeatConfig.checkIntervalMs);
    };

    // 创建包装后的回调函数
    const wrappedCallbacks = {
      onOpen: (response: Response) => {
        // 连接成功时启动心跳检测
        startHeartbeatCheck();

        // 调用原始onOpen回调
        if (config.onOpen) {
          config.onOpen(response);
        }
      },

      onMessage: (message: EventSourceMessage) => {
        // 收到任何消息都更新最后事件时间戳
        lastEventTimestamp = Date.now();

        if (message.event === EventType.PING) {
          return;
        }

        // 调用原始onMessage回调
        config.onMessage(message);
      },

      onError: (error: Error) => {
        // 错误时清理心跳检测
        if (heartbeatCheckTimer) {
          clearInterval(heartbeatCheckTimer);
          heartbeatCheckTimer = null;
        }

        // 调用原始onError回调
        if (config.onError) {
          config.onError(error);
        }
      },

      onClose: () => {
        // 关闭时清理心跳检测
        if (heartbeatCheckTimer) {
          clearInterval(heartbeatCheckTimer);
          heartbeatCheckTimer = null;
        }

        // 调用原始onClose回调
        if (config.onClose) {
          config.onClose();
        }
      }
    };

    // 开始SSE连接
    fetchEventSource(url, {
      method: "GET",
      headers,
      signal: controller.signal,
      openWhenHidden: true, // 页面隐藏时保持连接
      onopen: async response => {
        wrappedCallbacks.onOpen(response);
      },
      onmessage: message => {
        wrappedCallbacks.onMessage(message);
      },
      onerror: error => {
        wrappedCallbacks.onError(error);
      },
      onclose: () => {
        wrappedCallbacks.onClose();
      }
    });

    // 返回一个对象，用于关闭连接
    return {
      close: () => {
        // 清理心跳检测定时器
        if (heartbeatCheckTimer) {
          clearInterval(heartbeatCheckTimer);
          heartbeatCheckTimer = null;
        }

        // 关闭连接
        if (controller) {
          controller.abort();
          controller = null;
          wrappedCallbacks.onClose();
        }
      }
    };
  }
}

export const http = new PureHttp();
